package com.weimob.mcloud.wechatwork.customer.mq.handler.externaluser;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.weimob.dq.client.api.DqFramework;
import com.weimob.mcloud.wechatwork.common.enums.CommonBizErrorEnum;
import com.weimob.mcloud.wechatwork.common.enums.MainBizDomainEnum;
import com.weimob.mcloud.wechatwork.common.enums.SubBizDomainEnum;
import com.weimob.mcloud.wechatwork.common.utils.BizErrorCodeGenerator;
import com.weimob.mcloud.wechatwork.core.adapter.enums.cdp.CDPMarkTypeEnum;
import com.weimob.mcloud.wechatwork.core.adapter.enums.cdp.CdpMarkMessageEventEnum;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.bos.request.QueryBosRequestDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.bos.response.MerchantDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.cdp.request.customer.CDPUserMarkDTO;
import com.weimob.mcloud.wechatwork.core.adapter.service.BosAdapterService;
import com.weimob.mcloud.wechatwork.core.adapter.service.OneCrmAdapterService;
import com.weimob.mcloud.wechatwork.core.adapter.service.cdp.CdpUserAdapterService;
import com.weimob.mcloud.wechatwork.core.base.SingleRequest;
import com.weimob.mcloud.wechatwork.core.entity.privatesphere.PrivateSphere;
import com.weimob.mcloud.wechatwork.core.entity.relation.CustomerEmployeeRelation;
import com.weimob.mcloud.wechatwork.core.entity.relation.customer.Customer;
import com.weimob.mcloud.wechatwork.core.entity.relation.customer.CustomerLoseLog;
import com.weimob.mcloud.wechatwork.core.entity.relation.employee.Employee;
import com.weimob.mcloud.wechatwork.core.enums.customer.CustomerStatusEnum;
import com.weimob.mcloud.wechatwork.core.enums.customer.ExternalUserTypeEnum;
import com.weimob.mcloud.wechatwork.core.enums.employee.EmployeeActiveStatusEnum;
import com.weimob.mcloud.wechatwork.core.enums.employee.EmployeeStatusEnum;
import com.weimob.mcloud.wechatwork.core.service.customer.CustomerLoseService;
import com.weimob.mcloud.wechatwork.core.service.customer.CustomerService;
import com.weimob.mcloud.wechatwork.core.service.employee.EmployeeService;
import com.weimob.mcloud.wechatwork.core.service.privatesphere.PrivateSphereService;
import com.weimob.mcloud.wechatwork.core.service.statistic.StatisticsService;
import com.weimob.mcloud.wechatwork.customer.config.DqConfig;
import com.weimob.mcloud.wechatwork.customer.constant.RedisLockConstant;
import com.weimob.mcloud.wechatwork.customer.convertor.bos.PrivateSphereCovert;
import com.weimob.mcloud.wechatwork.customer.domain.*;
import com.weimob.mcloud.wechatwork.customer.externalDependencyProxy.usermanagement.EmployeeProxy;
import com.weimob.mcloud.wechatwork.customer.mq.handler.externaluser.retry.AddExternalUserRetry;
import com.weimob.mcloud.wechatwork.customer.mq.model.ChatGroupFacade;
import com.weimob.mcloud.wechatwork.customer.mq.model.CustomerLoseEvent;
import com.weimob.mcloud.wechatwork.customer.redis.RedisService;
import com.weimob.mcloud.wechatwork.customer.service.LoseMessageService;
import com.weimob.mcloud.wechatwork.customer.service.MsgNoticeService;
import com.weimob.mcloud.wechatwork.customer.service.common.CustomerCommonService;
import com.weimob.mcloud.wechatwork.customer.service.impl.ArtemisService;
import com.weimob.mcloud.wechatwork.customer.service.user.base.BaseRequest;
import com.weimob.mcloud.wechatwork.customer.service.user.base.BasicInfo;
import com.weimob.mcloud.wechatwork.customer.service.user.base.PrivateSphereDTO;
import com.weimob.mcloud.wechatwork.customer.service.user.constant.RedisKeyConstant;
import com.weimob.mcloud.wechatwork.customer.service.user.enums.CDPFlowStatusEnum;
import com.weimob.mcloud.wechatwork.customer.service.user.enums.CustomerLoseTypeEnum;
import com.weimob.mcloud.wechatwork.customer.service.user.exception.BizException;
import com.weimob.mcloud.wechatwork.customer.service.user.module.bo.customer.AdminInfo;
import com.weimob.mcloud.wechatwork.customer.service.user.module.bo.customer.EmployDeleteCustomerAlarmBO;
import com.weimob.mcloud.wechatwork.customer.service.user.module.dto.msg.CustomerLoseNoticeDTO;
import com.weimob.mcloud.wechatwork.customer.service.user.service.CustomerLoseExport;
import com.weimob.mcloud.wechatwork.customer.service.user.utils.BeanUtil;
import com.weimob.mcloud.wechatwork.customer.service.user.utils.Utils;
import com.weimob.mcloud.wechatwork.customer.third.core.CustomerServiceProxy;
import com.weimob.mcloud.wechatwork.customer.third.customer.CustomerThird;
import com.weimob.saas.open.producer.interfaces.dto.OpenMessageDTO;
import com.weimob.saas.open.producer.interfaces.export.OpenMessageDubboService;
import com.weimob.soa.common.response.SoaResponse;
import com.weimob.soa.common.utils.SoaUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * Create Time: 2021年01月18日 16:11
 * 删除外部联系人事件
 *
 * @author maosheng.li
 **/
@Service
@Slf4j
public class DelCorpExternaluserHandler implements CorpExternalUserHandler {

    @Reference
    private CustomerService customerService;

    @Autowired
    private CustomerServiceProxy customerServiceProxy;

    @Reference
    private EmployeeService employeeService;

    @Autowired
    private ArtemisService artemisService;

    @Reference
    private PrivateSphereService privateSphereService;

    @Reference
    private OneCrmAdapterService oneCrmAdapterService;

    @Reference
    private CdpUserAdapterService cdpUserAdapterService;

    @Reference
    private OpenMessageDubboService openMessageDubboService;

    @Reference
    private BosAdapterService bosAdapterService;

    @Autowired
    private CustomerCommonService customerCommonService;

    @Autowired
    private AddCorpExternaluserSecondHandler addCorpExternaluserSecondHandler;

    @Autowired
    @Qualifier("statisticThreadPool")
    private ThreadPoolTaskExecutor statisticThreadPool;

    @Reference
    private StatisticsService statisticsService;

    @Autowired
    private LoseMessageService loseMessageService;

    @Autowired
    private MsgNoticeService msgNoticeService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private CustomerThird customerThird;

    @Autowired
    private RedissonClient redissonClient;

    @Reference
    private CustomerLoseService customerLoseService;

    @Autowired
    private CustomerLoseExport customerLoseExport;

    @Autowired
    private DqFramework dqClient;

    @Value("${customer.lose.delaytime:2}")
    private Integer customerLoseDelaytime;

    @Resource(name = "customerRelationChangeProcessThreadPool")
    ThreadPoolTaskExecutor customerRelationChangeProcessThreadPool;

    @Resource
    ChatGroupFacade chatGroupFacade;

    /**
     * 企微助手产品id
     */
    @Value("${aewc.productId:203}")
    private Long aewcProductId;

    @Autowired
    private AddExternalUserRetry addExternalUserRetry;

    @Autowired
    private EmployeeProxy employeeProxy;


    @Override
    public SoaResponse<?, ?> handleCorpExternalUser(ExternalUserChangeInfo externalUserChageInfo) {
        log.info("新中台客户流失handleCorpExternalUser：request {}", JSON.toJSONString(externalUserChageInfo));
        //1、员工删客户、客户删员工复用同一套逻辑
        String userId = externalUserChageInfo.getUserID();
        String corpId = externalUserChageInfo.getToUserName();
        String externalUserId = externalUserChageInfo.getExternalUserID();

        if (externalUserChageInfo.getLoseType() == null) {
            //1.1 如果上游流失类型为空，那么就是员工删客户事件
            externalUserChageInfo.setLoseType(CustomerLoseTypeEnum.EMPLOYEE_DEL_CUSTOMER.getCode());
        }

        //1、判断是否绑定企微产品私域
        PrivateSphere privateSphereRequest = new PrivateSphere();
        privateSphereRequest.setCorpId(corpId);
        privateSphereRequest.setProductId(aewcProductId);
        privateSphereRequest.setTemplateId(externalUserChageInfo.getTemplateId());
        SoaResponse<PrivateSphere, Void> fetchPrivateSphere = privateSphereService.fetch(privateSphereRequest);
        if (!SoaUtil.isSucc(fetchPrivateSphere)) {
            //2.1 私域返回错误，打印错误
            log.warn("消费删除外部联系人消息查询私域信息失败, corpId:{}", corpId);
            String errorCode = BizErrorCodeGenerator.generate(MainBizDomainEnum.CUSTOMER_MANAGEMENT
                    , SubBizDomainEnum.CUSTOMER_LIST, CommonBizErrorEnum.ABNORMAL_DATA);
            return SoaUtil.error(errorCode, "消费删除外部联系人消息查询私域信息失败" + externalUserId, null);
        }
        PrivateSphere privateSphere = fetchPrivateSphere.getResponseVo();
        Long bosId = privateSphere.getBosId();
        externalUserChageInfo.setBosId(bosId);
        //2、判断员工是否存在 且在可见范围
        Employee employeeResult = employeeProxy.fetchEmployeeById(privateSphere, userId, null);
        if (Objects.isNull(employeeResult)) {
            log.warn("添加客户, 企微助手查询本地员工为空, userId:{}", userId);
            String errorCode = BizErrorCodeGenerator.generate(MainBizDomainEnum.CUSTOMER_MANAGEMENT
                    , SubBizDomainEnum.CUSTOMER_LIST, CommonBizErrorEnum.ABNORMAL_DATA);
            return SoaUtil.error(errorCode, "流失客户处理, 企微助手查询本地员工数据失败, userId:" + userId, null);
        }
        if (Objects.isNull(employeeResult.getStatus())) {
            log.warn("客户删除事件-对应员工状态为null,employeeId:{},corpId:{}", employeeResult.getId(), corpId);
            String errorCode = BizErrorCodeGenerator.generate(MainBizDomainEnum.CUSTOMER_MANAGEMENT
                    , SubBizDomainEnum.CUSTOMER_LIST, CommonBizErrorEnum.ABNORMAL_DATA);
            return SoaUtil.error(errorCode, "客户删除事件-对应员工状态为null,userId:" + userId, null);
        }
        // 默认有效 员工未授权或不在坐席则无效落数据
        List<Integer> statusList = Lists.newArrayList(EmployeeStatusEnum.ACTIVATED.getCode(), EmployeeStatusEnum.DISABLED.getCode(),
                EmployeeStatusEnum.INACTIVE.getCode(), EmployeeStatusEnum.QUITED.getCode());
        CustomerStatusEnum customerStatus = CustomerStatusEnum.DEFAULT;
        if (employeeResult.getActiveStatus() != null && EmployeeActiveStatusEnum.INACTIVE.getCode() == employeeResult.getActiveStatus().getCode()
                || !statusList.contains(employeeResult.getStatus().getCode())) {
            customerStatus = CustomerStatusEnum.UNAUTHORIZED;
        }

        //3、校验流失客户信息数据
        Customer customerResponse = customerServiceProxy.fetchCustomer(null, externalUserId, privateSphere);

        Long delEventTime = externalUserChageInfo.getCreateTime();
        if (customerResponse == null) {
            //4、理论上肯定存在客户信息，打印错误
            log.warn("handleCorpExternalUser 流失客户未查询到客户信息, corpId:{}, externalUserId:{}", corpId, externalUserId);
            //获取添加事件的时间，判断是否大于，大于则重发，小于则不处理
            String msgUk = String.format(RedisKeyConstant.ADD_CORP_USER_EXTERNAL_USER_CREATE_TIME, bosId, corpId, externalUserId, userId);
            Object timeObject = redisService.get(msgUk);
            if (Objects.nonNull(timeObject)) {
                Long addEventTime = Long.parseLong(String.valueOf(timeObject));
                if (addEventTime.compareTo(delEventTime) < 0) {
                    //重发
                    addExternalUserRetry.msgRetry(externalUserChageInfo);
                }
                log.warn("handleCorpExternalUser delEventTime:{},addEventTime:{}, corpId:{}, externalUserId:{}", delEventTime, timeObject, corpId, externalUserId);
            }
            String errorCode = BizErrorCodeGenerator.generate(MainBizDomainEnum.CUSTOMER_MANAGEMENT
                    , SubBizDomainEnum.CUSTOMER_LIST, CommonBizErrorEnum.ABNORMAL_DATA);
            return SoaUtil.error(errorCode, "流失客户未查询到客户信息，externalUserId:" + externalUserId, null);
        }
        String customerId = customerResponse.getId();
        //防并发
        RLock lock = redissonClient.getLock(String.format(RedisKeyConstant.DEL_CORP_USER_EXTERNAL_USER_LOCK,
                corpId, customerId, employeeResult.getId(), externalUserChageInfo.getLoseType()));
        try {
            //尝试加锁，最多等待0秒，上锁以后3秒自动解锁  针对同一员工和客户并发，重复的直接放过
            Boolean lockResult = lock.tryLock(0, 3, TimeUnit.SECONDS);
            log.info("deluser lockResult:{}", lockResult);
            if (!lockResult) {
                String errorCode = BizErrorCodeGenerator.generate(MainBizDomainEnum.CUSTOMER_MANAGEMENT
                        , SubBizDomainEnum.CUSTOMER_LIST, CommonBizErrorEnum.ABNORMAL_DATA);
                return SoaUtil.error(errorCode, "流失客户幂等锁过滤" + externalUserId, null);
            }


            //5.2 查询当前流失客户员工关系

            List<CustomerEmployeeRelation> relationList;
            try {
                relationList = customerServiceProxy.fetchCustomerEmployeeRelation(customerId, employeeResult.getId(), privateSphere, null, null, null);
            } catch (Exception e) {
                log.error("查询客户员工关系失败, customerId:{},empId:{},e", customerId, employeeResult.getId(), e);
                String errorCode = BizErrorCodeGenerator.generate(MainBizDomainEnum.CUSTOMER_MANAGEMENT
                        , SubBizDomainEnum.CUSTOMER_LIST, CommonBizErrorEnum.ABNORMAL_DATA);
                return SoaUtil.error(errorCode, "查询客户员工关系失败" + externalUserId, null);
            }
            if (CollectionUtils.isEmpty(relationList)) {
                log.warn("流失客户未查询到客户员工关系, customerId:{},empId:{}", customerId, employeeResult.getId());
                String errorCode = BizErrorCodeGenerator.generate(MainBizDomainEnum.CUSTOMER_MANAGEMENT
                        , SubBizDomainEnum.CUSTOMER_LIST, CommonBizErrorEnum.ABNORMAL_DATA);
                return SoaUtil.error(errorCode, "查询客户员工关系失败" + externalUserId, null);
            }

            CustomerEmployeeRelation customerEmployeeRelationResp = relationList.get(0);

            CustomerEmployeeRelation customerEmpRelRequest = new CustomerEmployeeRelation();
            customerEmpRelRequest.setCorpId(corpId);
            customerEmpRelRequest.setFriended(false);
            customerEmpRelRequest.setEmployee(employeeResult);
            customerEmpRelRequest.setCustomerId(customerId);
            customerEmpRelRequest.setLoseTime(new Date());
            //5.3 更新流失类型（历史数据同步会用到）
            if (!CustomerLoseTypeEnum.DOUBLE_DELETE.getCode().equals(customerEmployeeRelationResp.getLoseType())) {
                //非双向删除情况（防止并发）
                if (CustomerLoseTypeEnum.CUSTOMER_DEL_EMPLOYEE.getCode().equals(externalUserChageInfo.getLoseType())) {
                    //此次事件是客户删除员工
                    customerEmpRelRequest.setLoseType(CustomerLoseTypeEnum.CUSTOMER_DEL_EMPLOYEE.getCode());
                    if (!customerEmployeeRelationResp.getFriended()
                            && CustomerLoseTypeEnum.EMPLOYEE_DEL_CUSTOMER.getCode().equals(customerEmployeeRelationResp.getLoseType())) {
                        //已经是非好友，并且员工之前删除了客户，则置为双线删除（并且标记是员工先删除的客户）
                        customerEmpRelRequest.setLoseType(CustomerLoseTypeEnum.DOUBLE_DELETE.getCode());
                    }
                } else {
                    customerEmpRelRequest.setLoseType(CustomerLoseTypeEnum.EMPLOYEE_DEL_CUSTOMER.getCode());
                    if (!customerEmployeeRelationResp.getFriended()
                            && CustomerLoseTypeEnum.CUSTOMER_DEL_EMPLOYEE.getCode().equals(customerEmployeeRelationResp.getLoseType())) {
                        //已经是非好友，并且客户之前删除了员工，则置为双线删除（并且标记是员工先删除的客户）
                        customerEmpRelRequest.setLoseType(CustomerLoseTypeEnum.DOUBLE_DELETE.getCode());
                    }
                }
            }

            //5.4 更新客户员工关系
            try {
                customerService.updateCustomerEmployeeRelation(customerEmpRelRequest);
            } catch (Exception e) {
                log.error("更新客户员工关系失败e:", e);
                throw new BizException("更新客户员工关系失败");
            }

            //6、客户流失记录 幂等处理
            String key = String.format(RedisLockConstant.customerLose, corpId, customerId, employeeResult.getId());
            boolean dumpFlag = redisService.setNX(key, "1", RedisLockConstant.lockTime, TimeUnit.SECONDS);
            if (dumpFlag) {
                CustomerLoseLog customerLoseLog = new CustomerLoseLog();
                customerLoseLog.setPrivateSphereId(privateSphere.getPrivateSphereId());
                customerLoseLog.setCustomerId(customerId);
                customerLoseLog.setOrgUserId(customerEmployeeRelationResp.getEmployee().getId());
                customerLoseLog.setLoseTime(new Date());
                customerLoseLog.setLoseType(externalUserChageInfo.getLoseType());
                customerLoseLog.setAddTime(customerEmployeeRelationResp.getAddTime());
                //留存天数 = 客户流失时间-客户添加当前员工时间
                long retentionDay = System.currentTimeMillis() - customerEmployeeRelationResp.getAddTime().getTime();
                customerLoseLog.setRetentionDays(retentionDay / 1000 / 60 / 60 / 24);
                SingleRequest<CustomerLoseLog> request = new SingleRequest(customerLoseLog);
                request.setPrivateSphere(privateSphere);
                try {
                    log.info("存客户流失关系, customerLoseServiceInsert, request:{}", JSON.toJSONString(customerLoseLog));
                    SoaResponse<CustomerLoseLog, ?> insert = customerLoseService.insert(request);
                    CustomerLoseLog unpack1 = SoaUtil.unpack(insert);
                    customerLoseLog.setId(unpack1.getId());
                } catch (Exception e) {
                    log.error("存客户流失关系失败:", e);
                    throw new BizException("存客户流失关系失败");
                }
                //6.1 延迟队列赛数据，用来获取最后一次触达信息
                dqClient.sendMsg(DqConfig.CUSTOMER_LOSE_MSG, customerLoseDelaytime, TimeUnit.HOURS, JSON.toJSONString(customerLoseLog),
                        null);
            }
            String employeeId = employeeResult.getId();
            //7、流失提醒处理
            //存完客户流失关系后，存一份数据到redis，判断是否触及客户流失告警
            //一个员工一天只会告警一次，如果这个key已经告警了，把这个key删掉，下一次删除客户的时候不在记录这个key的信息
            if (CustomerLoseTypeEnum.EMPLOYEE_DEL_CUSTOMER.getCode().equals(externalUserChageInfo.getLoseType())) {
                String recordKey = RedisKeyConstant.EMPLOYEE_DEL_CUSTOMER_WARN_RECORD + privateSphere.getPrivateSphereId() + employeeId;
                String warnKey = RedisKeyConstant.EMPLOYEE_DEL_CUSTOMER_WARN + privateSphere.getPrivateSphereId() + employeeId;
                if (Objects.isNull(redisService.get(recordKey))) {
                    redisService.setAdd(warnKey, customerId, Utils.getTodayEndTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
                    Long size = redisService.getSize(warnKey);
                    BaseRequest baseRequest = new BaseRequest();
                    BasicInfo basicInfo = new BasicInfo();
                    BeanUtil.copyProperties(privateSphere, basicInfo);
                    baseRequest.setBasicInfo(basicInfo);
                    EmployDeleteCustomerAlarmBO alarmBO = SoaUtil.unpack(customerLoseExport.getAlarmDetail(baseRequest));

                    if (alarmBO != null && alarmBO.getDeleteNum() != null && size >= alarmBO.getDeleteNum()
                            && CollectionUtils.isNotEmpty(alarmBO.getNoticeAdmin())) {
                        //触发报警---发送报警提醒
                        List<String> employeeIds = Lists.newArrayList();
                        for (AdminInfo adminInfo : alarmBO.getNoticeAdmin()) {
                            employeeIds.add(adminInfo.getOrgUserId());
                        }
                        EmployeeDeleteCustomerMsgDTO employeeDeleteCustomerMsgDTO = new EmployeeDeleteCustomerMsgDTO();
                        employeeDeleteCustomerMsgDTO.setPrivateSphere(privateSphere);
                        employeeDeleteCustomerMsgDTO.setNoticeEmployeeIds(employeeIds);
                        employeeDeleteCustomerMsgDTO.setDeleteNum(alarmBO.getDeleteNum());
                        employeeDeleteCustomerMsgDTO.setDeleteEmployeeName(employeeResult.getName());
                        msgNoticeService.employeeDeleteCustomerWarnNotice(employeeDeleteCustomerMsgDTO);
                        //触发报警之后删掉这个key，记录recordKey
                        redisService.delete(warnKey);
                        redisService.setNX(recordKey, employeeId, Utils.getTodayEndTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
                    }
                }
            }

            //8、发送流失提醒逻辑
            try {
                sendLoseNotice(customerResponse, privateSphere, externalUserChageInfo.getLoseType(), employeeResult);
            } catch (Exception e) {
                log.error("删除好友事件，发送流失提醒消息失败, error:", e);
            }


            //11、客户群好友关系维护
            customerRelationChangeProcessThreadPool.execute(() -> {
                chatGroupFacade.execute(privateSphere, customerResponse.getExternalUserid(), customerId, true);
            });

            // 查询主客户wid
            Long superWid = customerThird.getSuperWid(bosId, externalUserId, privateSphere.getCorpId());
            if (Objects.isNull(superWid)) {
                log.warn("删除好友消息处理,查询主客户wid失败, bosId:{}, externalUserId:{}, corpId:{}", bosId, externalUserId, privateSphere.getCorpId());
                String errorCode = BizErrorCodeGenerator.generate(MainBizDomainEnum.CUSTOMER_MANAGEMENT
                        , SubBizDomainEnum.CUSTOMER_LIST, CommonBizErrorEnum.ABNORMAL_DATA);
                return SoaUtil.error(errorCode, "删除好友消息处理,查询主客户wid失败" + externalUserId, null);
            }
            //10、发送二次消息给到裂变使用
            ArtemisBaseInfo artemisBaseInfo = new ArtemisBaseInfo();
            artemisBaseInfo.setTopic(ArtemisConstant.Topic.WECHATWORK_USER_CUSTOMER_LOSE_MSG);
            artemisBaseInfo.setProducer(ArtemisConstant.USER);

            CustomerLoseEvent customerLoseEvent = new CustomerLoseEvent();
            customerLoseEvent.setBosId(bosId);
            customerLoseEvent.setCorpId(customerResponse.getCorpId());
            customerLoseEvent.setEmployeeId(employeeResult.getId());
            customerLoseEvent.setCustomerId(customerResponse.getId());
            customerLoseEvent.setWid(superWid);
            customerLoseEvent.setTxUserId(employeeResult.getTxUserId());
            if (CustomerLoseTypeEnum.CUSTOMER_DEL_EMPLOYEE.getCode().equals(externalUserChageInfo.getLoseType())) {
                customerLoseEvent.setType(CustomerLoseTypeEnum.CUSTOMER_DEL_EMPLOYEE.getCode());
            } else {
                customerLoseEvent.setType(CustomerLoseTypeEnum.EMPLOYEE_DEL_CUSTOMER.getCode());
            }
            artemisBaseInfo.setEvent(customerLoseEvent);
            log.info("新中台客户流失二次分发消息：request {}", JSON.toJSONString(artemisBaseInfo));
            artemisService.sendToArtemis(artemisBaseInfo, bosId);

            try {
                QueryBosRequestDTO queryBosRequestDTO = new QueryBosRequestDTO();
                queryBosRequestDTO.setBosId(bosId);
                MerchantDTO merchantDTO = SoaUtil.unpack(bosAdapterService.queryWidByBosId(queryBosRequestDTO));

                OpenMessageDTO openMessageDTO = new OpenMessageDTO();
                openMessageDTO.setId(bosId + customerResponse.getExternalUserid() + userId + customerEmployeeRelationResp.getAddTime().getTime());
                openMessageDTO.setTopic(IpaasMsgConstant.Topic.IPAAS_CUSTOMER_LOSE_MSG);
                openMessageDTO.setEvent(IpaasMsgConstant.Event.DELETE);
                openMessageDTO.setBosId(bosId);
                openMessageDTO.setWid(merchantDTO.getWid());
                openMessageDTO.setOriginProductId(privateSphere.getProductId());
                openMessageDTO.setOriginProductInstanceId(privateSphere.getProductInstanceId());
                openMessageDTO.setMsgBody(JSON.toJSONString(customerLoseEvent));
                log.info("新中台客户流失二次分发ipass消息：request {}", JSON.toJSONString(artemisBaseInfo));
                openMessageDubboService.sendOpenMessage(openMessageDTO);
            } catch (Exception e) {
                log.error("新中台客户流失二次分发ipass消息失败:", e);
            }

            //12、客搜和cdp 业务处理
            //12.2、发送客户变更消息
            if (ExternalUserTypeEnum.WECHAT_CUSTOMER.equals(customerResponse.getExternalUserType())) {
                //外部联系人才进行客户搜索
                addCorpExternaluserSecondHandler.updateCustomerSearchMsg(superWid, bosId,
                        privateSphere.getProductInstanceId(), privateSphere.getProductId());
            }

            //12.3、客户删员工/员工删客户事件
            CDPUserMarkDTO cdpUserMarkDTO = new CDPUserMarkDTO();
            cdpUserMarkDTO.setuKey(String.valueOf(superWid));
            cdpUserMarkDTO.setuKeyType("wid");
            cdpUserMarkDTO.setsChannelType(203);
            cdpUserMarkDTO.setsChannelId(privateSphere.getProductInstanceId());
            cdpUserMarkDTO.setBosId(bosId);
            cdpUserMarkDTO.setUpdateTime(String.valueOf(delEventTime * 1000L));
            CdpDataJsonInfo cdpDataJsonInfo = new CdpDataJsonInfo();
            cdpDataJsonInfo.setProductInstanceId(privateSphere.getProductInstanceId());
            cdpDataJsonInfo.setWid(superWid);
            cdpDataJsonInfo.setCorpId(corpId);
            cdpDataJsonInfo.setExternalUserId(externalUserId);
            cdpDataJsonInfo.setWechatNickName(customerResponse.getName());
            cdpDataJsonInfo.setOrgUserId(employeeResult.getId());
            cdpDataJsonInfo.setOrgUserName(employeeResult.getName());
            cdpDataJsonInfo.setCustomerStatus(customerStatus.getCode());
            cdpUserMarkDTO.setDataJson(JSONObject.parseObject(JSON.toJSONString(cdpDataJsonInfo)));
            cdpUserMarkDTO.setCdpMarkTypeEnum(CDPMarkTypeEnum.CDP_USER_ACTION);
            if (CustomerLoseTypeEnum.CUSTOMER_DEL_EMPLOYEE.getCode().equals(externalUserChageInfo.getLoseType())) {
                cdpUserMarkDTO.setCdpMarkMessageEventEnum(CdpMarkMessageEventEnum.CUSTOMER_DEL_USER);
            } else {
                cdpUserMarkDTO.setCdpMarkMessageEventEnum(CdpMarkMessageEventEnum.DELETE_CUSTOMER);
            }
            log.info("新中台外部联系人流失CDP打点行为事件：request {}", JSON.toJSONString(cdpUserMarkDTO));
            cdpUserAdapterService.markCDPUserMsg(cdpUserMarkDTO);

            //12.4、判断是否流失发送事件（CDP需要客户和企业所有员工都流失的事件）
            List<CustomerEmployeeRelation> employeeRelations = null;
            try {
                employeeRelations = customerServiceProxy.fetchCustomerEmployeeRelation(customerId, null, privateSphere, CustomerStatusEnum.DEFAULT, null, null);
            } catch (Exception e) {
                log.error("删除好友事件，查询员工客户关系数据失败，error", e);
                String errorCode = BizErrorCodeGenerator.generate(MainBizDomainEnum.CUSTOMER_MANAGEMENT
                        , SubBizDomainEnum.CUSTOMER_LIST, CommonBizErrorEnum.ABNORMAL_DATA);
                return SoaUtil.error(errorCode, "删除好友事件，查询员工客户关系数据失败" + externalUserId, null);
            }
            //是否发送流失（如果双删的话是不需要发送流失事件）
            Boolean loseBiz = true;
            if (employeeRelations != null && employeeRelations.size() > 0) {
                CustomerEmployeeRelation currentRelation = null;
                for (CustomerEmployeeRelation employeeRelation : employeeRelations) {
                    if (employeeRelation.getFriended()) {
                        //好友状态说明未流失
                        loseBiz = false;
                    }
                    Employee emp = employeeRelation.getEmployee();
                    if (Objects.nonNull(emp) && Objects.nonNull(emp.getTxUserId())
                            && emp.getTxUserId().equals(userId)) {
                        currentRelation = employeeRelation;
                    }
                }
                if (currentRelation != null && loseBiz) {
                    //如果当前消息的员工和查出来的员工状态变成了双删 那么也是不需要发送流失事件的，单删的时候已经发送过了
                    if (CustomerLoseTypeEnum.DOUBLE_DELETE.getCode().equals(currentRelation.getLoseType())) {
                        loseBiz = false;
                    }
                }
            }
            if (loseBiz) {
                //流失发送cdp事件
                CDPUserMarkDTO loseCdpUserMarkDTO = new CDPUserMarkDTO();
                loseCdpUserMarkDTO.setuKey(String.valueOf(superWid));
                loseCdpUserMarkDTO.setuKeyType("wid");
                loseCdpUserMarkDTO.setsChannelType(203);
                loseCdpUserMarkDTO.setsChannelId(privateSphere.getProductInstanceId());
                loseCdpUserMarkDTO.setBosId(bosId);
                loseCdpUserMarkDTO.setUpdateTime(String.valueOf(System.currentTimeMillis()));
                loseCdpUserMarkDTO.setCdpMarkTypeEnum(CDPMarkTypeEnum.CDP_USER_ACTION);
                loseCdpUserMarkDTO.setCdpMarkMessageEventEnum(CdpMarkMessageEventEnum.LOSE_CUSTOMER);
                CdpDataJsonInfo loseCdpDataJsonInfo = new CdpDataJsonInfo();
                loseCdpDataJsonInfo.setWid(superWid);
                loseCdpDataJsonInfo.setCorpId(corpId);
                loseCdpDataJsonInfo.setExternalUserId(externalUserId);
                loseCdpUserMarkDTO.setDataJson(JSONObject.parseObject(JSON.toJSONString(loseCdpDataJsonInfo)));
                log.info("新中台外部联系人完全流失CDP打点行为事件：request {}", JSON.toJSONString(cdpUserMarkDTO));
                cdpUserAdapterService.markCDPUserMsg(loseCdpUserMarkDTO);

                // 有效的关系去属性打点
                if (CustomerStatusEnum.DEFAULT.getCode().equals(customerStatus.getCode())) {
                    cdpDataJsonInfo.setFlowStatus(CDPFlowStatusEnum.LOST_STATUS.getCode());
                    cdpUserMarkDTO.setDataJson(JSONObject.parseObject(JSON.toJSONString(cdpDataJsonInfo)));
                    cdpUserMarkDTO.setCdpMarkTypeEnum(CDPMarkTypeEnum.CDP_USER_ATTRIBUTE);
                    cdpUserMarkDTO.setCdpMarkMessageEventEnum(CdpMarkMessageEventEnum.CUSTOMER_ATTRIBUTE);
                    log.info("新中台外部联系人流失CDP打点属性事件：request {}", JSON.toJSONString(cdpUserMarkDTO));
                    cdpUserAdapterService.markCDPUserMsg(cdpUserMarkDTO);
                }
            }


        } catch (Exception e) {
            log.error("删除好友事件，DelCorpExternalUserHandler Exception:", e);
        } finally {
            if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return SoaUtil.ok(null);
    }

    private void sendLoseNotice(Customer customer, PrivateSphere privateSphere, Integer type, Employee employeeResult) {
        EmployeeStatusEnum status = employeeResult.getStatus();
        EmployeeActiveStatusEnum activeStatus = employeeResult.getActiveStatus();
        if (EmployeeActiveStatusEnum.INACTIVE.equals(activeStatus) || EmployeeStatusEnum.USER_UN_AUTHORIZATION.equals(status)) {
            log.warn("删除好友事件，发送客户流失提醒消息, 员工状态异常,empId:{},status:{},activeStatus:{}", employeeResult.getId(), status, activeStatus);
            return;
        }
        CustomerLoseNoticeDTO customerLoseNoticeDTO = new CustomerLoseNoticeDTO();
        PrivateSphereDTO privateSphereDTO = PrivateSphereCovert.privateSphereDTO(privateSphere);
        customerLoseNoticeDTO.setPrivateSphereDTO(privateSphereDTO);
        customerLoseNoticeDTO.setExternalUserId(customer.getExternalUserid());
        customerLoseNoticeDTO.setUserId(employeeResult.getTxUserId());
        customerLoseNoticeDTO.setExternalUserName(customer.getName());
        customerLoseNoticeDTO.setType(type);

        //流失提醒加幂等控制
        String corpId = privateSphere.getCorpId();
        String loseKey = String.format(RedisLockConstant.DelCorpExternaluser, corpId, customerLoseNoticeDTO.getExternalUserId(),
                customerLoseNoticeDTO.getUserId(), customerLoseNoticeDTO.getType());
        boolean loseFlag = redisService.setNXNew(loseKey, "30", RedisLockConstant.lockTime, TimeUnit.SECONDS);
        if (loseFlag) {
            //流失提醒消息发送
            log.info("删除好友事件，发送客户流失提醒消息, 处理类, DelCorpExternaluserHandler, request:{}", JSON.toJSONString(customerLoseNoticeDTO));
            msgNoticeService.customerLoseNotice(customerLoseNoticeDTO);
        }
    }
}
